Schedule Provider
The Schedule Provider is an interface that defines the contract for fetching trading schedule information for use in DXCharts. It provides the ability to retrieve details about trading sessions, their types, and the trading days they belong to. The implementation of this interface can retrieve data from remote services, databases, or other sources.
Interface Definition
/*** Interface defining the contract for providing trading schedules for use in DXCharts.** This interface allows implementing classes to fetch and provide detailed information about trading schedules* based on a specified trading hours identifier. Implementations of this interface may retrieve data from various* sources such as local databases, remote services, or in-memory caches.*/interface DxChartsScheduleProvider {/*** Retrieves the trading schedule associated with the specified trading hours identifier.** This method is designed to be used asynchronously, allowing the calling code to wait for the result* without blocking the main thread. The implementation should handle any necessary data fetching, parsing,* and error handling.** @param tradingHours A string identifier representing the specific trading hours for which to fetch the schedule.* This value should correspond to a valid trading hours identifier understood by the provider.* @return A [Schedule] object containing detailed trading schedule information, or null if no data is available* or an error occurs during the operation.*/suspend fun getSchedule(tradingHours: String): Schedule?}
When an instrument is changed on the chart, data is fetched by calling the getSchedule
function, which returns the corresponding schedule.
Schedule Data Structure
The Schedule
class represents the processed information about an instrument's trading hours. Each trading day consists of multiple sessions, and these sessions are categorized by type.
/*** Data class for storing processed information about instrument's trading hours** Trading hours are split by sessions [Schedule.Day.Session]** Every session belongs to a day [Schedule.Day]** Sessions can be of different types [Schedule.Day.Session.Type] (PRE_MARKET, REGULAR, AFTER_MARKET, NO_TRADING)** @property name Name of the instrument.* @property timeZone Time zone name of the instrument.* @property days List of trading days.*/data class Schedule(val name: String,val timeZone: String,val days: List<Day>) {/*** Data class for storing processed information about instrument's trading hours for a single day** Trading hours are split by sessions [Schedule.Day.Session]** Day is split by sessions** @property id ID of the day (e.g., 2021-11-08).* @property isHoliday Indicates whether the day is a holiday with no trading.* @property isShort Indicates whether the day is a short day with shorter trading hours.* @property sessions List of trading sessions.*/data class Day(val id: String,val isHoliday: Boolean,val isShort: Boolean,val sessions: List<Session>) {/*** Data class for storing processed information about instrument's trading hours for a single session** Trading hours are split by sessions** Session belongs to a day [Schedule.Day]** Sessions can be of different types [Schedule.Day.Session.Type] (PRE_MARKET, REGULAR, AFTER_MARKET, NO_TRADING)** @property startTime Start time of the session in the format "yyyy-MM-dd HH:mm:ss'+0000'".* @property endTime End time of the session in the format "yyyy-MM-dd HH:mm:ss'+0000'".* @property type Type of the session (NO_TRADING, PRE_MARKET, REGULAR, AFTER_MARKET).*/data class Session(val startTime: String,val endTime: String,val type: Type,) {enum class Type(val value: String) {NO_TRADING("NO_TRADING"),PRE_MARKET("PRE_MARKET"),REGULAR("REGULAR"),AFTER_MARKET("AFTER_MARKET")}}}}
Extended Hours Visualization
Extended hours are displayed on the chart as follows:
Implementation Example
Below is a default implementation of the DxChartsScheduleProvider
interface, which fetches schedule data using HTTP requests.
/*** Implementation of [DxChartsScheduleProvider] that fetches schedule information using HTTP requests.** This class provides a way to fetch trading schedule information from a remote service using HTTP POST requests.* The retrieved data is parsed into domain-specific objects for further use in the application.** @property token Authorization token for accessing the schedule service. This token is included as a header in the requests.*/class DxFeedHttpScheduleProvider(private val token: String = "") : DxChartsScheduleProvider {private val client = OkHttpClient()private val gson = Gson()/*** Fetches a trading schedule based on the provided trading hours identifier.** This method sends an HTTP POST request to the schedule service with the specified trading hours identifier.* If the response is successful, it parses the JSON response into a domain-specific [Schedule] object.** @param tradingHours Identifier of the trading hours to fetch the schedule for.* This value is included in the request body as part of the "schedules" field.* @return A [Schedule] object containing trading schedule details or null if an error occurs or no data is returned.*/override suspend fun getSchedule(tradingHours: String): Schedule? {val requestBody = gson.toJson(SchedulesRequestBody(schedules = listOf(tradingHours))).toRequestBody(JSON)val request = Request.Builder().url(TRADING_HOURS_PARSER_URL).addHeader("Authorization", token).method("POST", requestBody).build()val call = client.newCall(request)try {call.execute().use { response ->if (response.isSuccessful) {val body = response.body?.string() ?: return nullval itemsMapType =object : TypeToken<Collection<Map<String, SchedulesResponseItem>>>() {}.typeval parsedData = gson.fromJson<Collection<Map<String, SchedulesResponseItem>>>(body,itemsMapType)return parsedData.firstOrNull()?.values?.firstOrNull()?.schedule?.toDomainSchedule()} else {return null}}} catch (e: IOException) {return null}}/*** Converts [SchedulesResponseItem.Schedule] to the domain-specific [Schedule] object.** This method maps the internal representation of a schedule from the service response to the domain model used* in the application. It includes mapping for days and sessions within the schedule.** @return The converted [Schedule] object.*/private fun SchedulesResponseItem.Schedule.toDomainSchedule(): Schedule {return Schedule(name = this.name,timeZone = this.timeZone,days = this.days.map { day ->Schedule.Day(id = day.id,isHoliday = day.isHoliday,isShort = day.isShort,sessions = day.sessions.map { session ->Schedule.Day.Session(startTime = session.startTime,endTime = session.endTime,type = when (session.type) {SchedulesResponseItem.Schedule.Day.Session.Type.NO_TRADING ->Schedule.Day.Session.Type.NO_TRADINGSchedulesResponseItem.Schedule.Day.Session.Type.PRE_MARKET ->Schedule.Day.Session.Type.PRE_MARKETSchedulesResponseItem.Schedule.Day.Session.Type.REGULAR ->Schedule.Day.Session.Type.REGULARSchedulesResponseItem.Schedule.Day.Session.Type.AFTER_MARKET ->Schedule.Day.Session.Type.AFTER_MARKET})})})}/*** Data class representing the request body for fetching trading schedules.** @property schedules List of trading schedules to fetch.* @property start Start timestamp for the request.* @property timeZone Timezone for the request.*/private data class SchedulesRequestBody(@SerializedName("schedules") val schedules: List<String>,@SerializedName("start") val start: Long = System.currentTimeMillis() - SCHEDULE_PERIOD_MILLS,@SerializedName("tz") val timezone: String = "UTC")/*** Data class representing the response item structure from the trading hours parser service.** @property schedule schedule information containing trading days and sessions.*/private data class SchedulesResponseItem(val schedule: Schedule) {/*** Data class representing the trading schedule structure.** @property name Name of the schedule.* @property timeZone Timezone associated with the schedule.* @property days List of trading [Day]s.*/data class Schedule(val name: String,val timeZone: String,val days: List<Day>) {/*** Data class representing a trading day within the schedule.** @property id Identifier for the trading day.* @property isHoliday Indicates whether the day is a holiday.* @property isShort Indicates whether the trading day is shorter than usual.* @property sessions List of trading [Session]s within the day.*/data class Day(val id: String,val isHoliday: Boolean,val isShort: Boolean,val sessions: List<Session>) {/*** Data class representing a trading session within a trading day.** @property startTime Start time of the trading session.* @property endTime End time of the trading session.* @property type Type of the trading session (NO_TRADING, PRE_MARKET, REGULAR, AFTER_MARKET).*/data class Session(val startTime: String,val endTime: String,val type: Type,) {/*** Enum class defining possible types of trading sessions.** Values: [NO_TRADING], [PRE_MARKET], [REGULAR], [AFTER_MARKET]*/enum class Type {NO_TRADING,PRE_MARKET,REGULAR,AFTER_MARKET}}}}}/*** Companion object containing constants and configuration for the DxFeedHttpScheduleProvider class.** @property JSON Media type for JSON requests.* @property SCHEDULE_PERIOD_MILLS Milliseconds in a year for scheduling purposes.* @property TRADING_HOURS_PARSER_URL URL for the trading hours parser service.*/companion object {private val JSON: MediaType = "application/json; charset=utf-8".toMediaTypeOrNull()!!private const val TRADING_HOURS_PARSER_URL ="https://tools.dxfeed.com/schedule-view/per-calendar-day"private const val SCHEDULE_PERIOD_MILLS = 1000L * 60L * 60L * 24L * 365L}}